package com.hyk.commonLib.common.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ViewFlipper;

import androidx.annotation.AnimRes;
import androidx.annotation.NonNull;

import com.hyk.commonLib.R;
import com.hyk.commonLib.common.utils.ListUtils;

import java.util.ArrayList;
import java.util.List;

public class MarqueeView<T, VIEW extends View> extends ViewFlipper {

    private int interval = 3000;
    private boolean hasSetAnimDuration = false;
    private int animDuration = 1000;

    private int direction = DIRECTION_BOTTOM_TO_TOP;
    private static final int DIRECTION_BOTTOM_TO_TOP = 0;
    private static final int DIRECTION_TOP_TO_BOTTOM = 1;
    private static final int DIRECTION_RIGHT_TO_LEFT = 2;
    private static final int DIRECTION_LEFT_TO_RIGHT = 3;

    @AnimRes
    private int inAnimResId = R.anim.anim_marquee_view_bottom_in;
    @AnimRes
    private int outAnimResId = R.anim.anim_marquee_view_top_out;

    private boolean isAnimStart = false;

    private int position;
    private List<T> messages = new ArrayList<>();
    private Adapter<T, VIEW> adapter;

    public MarqueeView(Context context) {
        this(context, null);
    }

    public MarqueeView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs, 0);
    }

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MarqueeViewStyle, defStyleAttr, 0);

        interval = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvInterval, interval);
        hasSetAnimDuration = typedArray.hasValue(R.styleable.MarqueeViewStyle_mvAnimDuration);
        animDuration = typedArray.getInteger(R.styleable.MarqueeViewStyle_mvAnimDuration, animDuration);

        if (typedArray.hasValue(R.styleable.MarqueeViewStyle_mvDirection)) {
            direction = typedArray.getInt(R.styleable.MarqueeViewStyle_mvDirection, direction);
            switch (direction) {
                case DIRECTION_BOTTOM_TO_TOP:
                    inAnimResId = R.anim.anim_marquee_view_bottom_in;
                    outAnimResId = R.anim.anim_marquee_view_top_out;
                    break;
                case DIRECTION_TOP_TO_BOTTOM:
                    inAnimResId = R.anim.anim_marquee_view_top_in;
                    outAnimResId = R.anim.anim_marquee_view_bottom_out;
                    break;
                case DIRECTION_RIGHT_TO_LEFT:
                    inAnimResId = R.anim.anim_marquee_view_right_in;
                    outAnimResId = R.anim.anim_marquee_view_left_out;
                    break;
                case DIRECTION_LEFT_TO_RIGHT:
                    inAnimResId = R.anim.anim_marquee_view_left_in;
                    outAnimResId = R.anim.anim_marquee_view_right_out;
                    break;
            }
        } else {
            inAnimResId = R.anim.anim_marquee_view_bottom_in;
            outAnimResId = R.anim.anim_marquee_view_top_out;
        }

        typedArray.recycle();
        setFlipInterval(interval);
    }

    /**
     * 根据字符串列表，启动翻页公告
     *
     * @param messages 字符串列表
     */
    public void startWithList(List<T> messages) {
        startWithList(messages, inAnimResId, outAnimResId);
    }

    /**
     * 根据字符串列表，启动翻页公告
     *
     * @param messages     字符串列表
     * @param inAnimResId  进入动画的resID
     * @param outAnimResID 离开动画的resID
     */
    public void startWithList(List<T> messages, @AnimRes int inAnimResId, @AnimRes int outAnimResID) {
        if (ListUtils.isEmpty(messages)) return;
        setMessages(messages);
        postStart(inAnimResId, outAnimResID);
    }

    private void postStart(final @AnimRes int inAnimResId, final @AnimRes int outAnimResID) {
        post(() -> start(inAnimResId, outAnimResID));
    }

    private void start(final @AnimRes int inAnimResId, final @AnimRes int outAnimResID) {
        removeAllViews();
        clearAnimation();
        // 检测数据源
        if (messages == null || messages.isEmpty()) {
            throw new RuntimeException("The messages cannot be empty!");
        }
        position = 0;
        addView(createTextView(messages.get(position)));

        if (messages.size() > 1) {
            setInAndOutAnimation(inAnimResId, outAnimResID);
            startFlipping();
        }

        if (getInAnimation() != null) {
            getInAnimation().setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    if (isAnimStart) {
                        animation.cancel();
                    }
                    isAnimStart = true;
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    position++;
                    if (position >= messages.size()) {
                        position = 0;
                    }
                    View view = createTextView(messages.get(position));
                    if (view.getParent() == null) {
                        addView(view);
                    }
                    isAnimStart = false;
                }

                @Override
                public void onAnimationRepeat(Animation animation) {
                }
            });
        }
    }

    private VIEW createTextView(T marqueeItem) {
        VIEW view = (VIEW) getChildAt((getDisplayedChild() + 1) % 3);
        Holder<T, VIEW> holder;
        if (view == null) {
            holder = adapter.createView(this);
            view = (VIEW) holder.itemView;
        } else {
            holder = (Holder<T, VIEW>) view.getTag();
        }
        holder.position = position;
        holder.item = marqueeItem;

        adapter.bindView(holder, marqueeItem);
        view.setTag(holder);
        return view;
    }

    public List<T> getMessages() {
        return messages;
    }

    public void setMessages(List<T> messages) {
        this.messages = messages;
    }

    /**
     * 设置进入动画和离开动画
     *
     * @param inAnimResId  进入动画的resID
     * @param outAnimResID 离开动画的resID
     */
    private void setInAndOutAnimation(@AnimRes int inAnimResId, @AnimRes int outAnimResID) {
        Animation inAnim = AnimationUtils.loadAnimation(getContext(), inAnimResId);
        if (hasSetAnimDuration) inAnim.setDuration(animDuration);
        setInAnimation(inAnim);

        Animation outAnim = AnimationUtils.loadAnimation(getContext(), outAnimResID);
        if (hasSetAnimDuration) outAnim.setDuration(animDuration);
        setOutAnimation(outAnim);
    }

    public void setAdapter(Adapter<T, VIEW> adapter) {
        this.adapter = adapter;
    }

    public abstract static class Adapter<T, VIEW extends View> {
        @NonNull
        public abstract Holder<T, VIEW> createView(ViewGroup parentView);

        public abstract void bindView(Holder<T, VIEW> holder, T item);
    }

    public static class Holder<T, VIEW extends View> {
        private final VIEW itemView;
        private int position;
        private T item;

        public Holder(VIEW itemView) {
            this.itemView = itemView;
        }

        public int getPosition() {
            return position;
        }

        public View getItemView() {
            return itemView;
        }

        public T getItem() {
            return item;
        }
    }
}
